import { IRect, IVec2 } from "../../util/Defined";
import { TypeUtil } from "../../util/TypeUtil";
import { Intersection } from "../Intersection";
import { Matrix } from "../math/Matrix";
import { Vec2 } from "../math/Vec2";
import { BaseShape, ShapeType } from "./BaseShape";
import { CircleShape } from "./CircleShape";
import { PolygonShape } from "./PolygonShape";

/**
 * 盒子图形
 */
export class BoxShape extends BaseShape implements IRect {

    readonly worldPolygon: readonly Vec2[] = [new Vec2(), new Vec2(), new Vec2(), new Vec2()];

    protected _width: number = 0;
    protected _height: number = 0;
    protected _halfWidth: number = 0;
    protected _halfHeight: number = 0;

    get width() {
        return this._width;
    }

    set width(v: number) {
        this._width = v;
        this._halfWidth = v / 2;
    }

    get height() {
        return this._height;
    }

    set height(v: number) {
        this._height = v;
        this._halfHeight = v / 2;
    }

    /**
     * 设置宽高
     * @param width 
     * @param height 
     */
    setSize(width: number, height: number) {
        this.width = width;
        this.height = height;
        return this;
    }

    getType(): ShapeType {
        return ShapeType.box;
    }

    update(pos: Readonly<IVec2>, trans?: Readonly<Matrix>): this {
        const aabb = this.worldAABB.setRect(
            this.x - this._halfWidth,
            this.y - this._halfHeight,
            this._width,
            this._height,
        );

        const [wpLb, wpRb, wpRt, wpLt] = this.worldPolygon;

        const left = aabb.x;
        const bottom = aabb.y;
        const right = left + aabb.width;
        const top = bottom + aabb.height;

        wpLb.setPos(left, bottom);
        wpRb.setPos(right, bottom);
        wpRt.setPos(right, top);
        wpLt.setPos(left, top);

        if (trans) {
            trans.transformPointN(wpLb);
            trans.transformPointN(wpRb);
            trans.transformPointN(wpRt);
            trans.transformPointN(wpLt);

            const minX = Math.min(wpLb.x, wpRb.x, wpRt.x, wpLt.x);
            const minY = Math.min(wpLb.y, wpRb.y, wpRt.y, wpLt.y);
            const maxX = Math.max(wpLb.x, wpRb.x, wpRt.x, wpLt.x);
            const maxY = Math.max(wpLb.y, wpRb.y, wpRt.y, wpLt.y);

            aabb.setRect(
                minX,
                minY,
                maxX - minX,
                maxY - minY
            );
        }

        wpLb.addPosTo(pos);
        wpRb.addPosTo(pos);
        wpRt.addPosTo(pos);
        wpLt.addPosTo(pos);
        aabb.addPosTo(pos);

        return this;
    }

    testCollide(shape: Readonly<BaseShape>): boolean {
        if (!Intersection.rectRect(this.worldAABB, shape.worldAABB)) {
            return false;
        }

        switch (shape.getType()) {
            case ShapeType.circle:
                return Intersection.polygonCircle2(this.worldPolygon, (shape as CircleShape).worldCircle);
            case ShapeType.rect:
                return Intersection.rectPolygon(shape.worldAABB, this.worldPolygon);
            case ShapeType.box:
            case ShapeType.polygon:
                return Intersection.polygonPolygon(this.worldPolygon, (shape as BoxShape | PolygonShape).worldPolygon);
        }

        throw new Error(`未实现碰撞方法：${TypeUtil.getCls(this).name} -> ${TypeUtil.getCls(shape).name}`);
    }

}